
	.386
if ?FLAT
	.MODEL FLAT, stdcall
else
	.MODEL SMALL, stdcall
endif
	option casemap:none
	option proc:private
	option dotname

	include winbase.inc
	include dkrnl32.inc
	include macros.inc

?RTCRES	equ 1	;use RTC timer for ms resolution on winNT/win9x?/DosEmu?

?INIT	equ 1

if ?INIT
.BASE$IA SEGMENT dword public 'DATA'
	DD offset Init
.BASE$IA ENDS
endif

	.data

g_dwGetTimerValue dd offset _GetTimerValue
g_dwGetTimerValuems dd offset _GetTimerValuems
if ?INIT
g_bInit	db 0
endif

	.code

;--- port 0043h
;--- bit 6-7: 11 = read back counter
;--- bit 4-5: 00 = read counter status (1 byte), then value (2 byte)
;--- bit 1-3: 001 = select counter 0
;--- bit 0: reserved

;--- the value returned is EDX (timer ticks) + AX (timer counter)
;--- in 1/1.193.180 sec units

_GetTimerValue proc
tryagain:

;	@noints			;22.10.2020 disabled

	mov edx,@flat:[046ch] 
	mov al,0C2h		;read timer 0 status + value low/high
	out 43h, al
	xchg edx, edx
	in al,40h
	mov cl,al		;CL = status
	xchg edx, edx
	in al,40h
	mov ah, al		;AH = value low
	xchg edx, edx
	in al,40h		;AL = value high

;	@restoreints	;22.10.2020 disabled

	test cl,40h		;was latch valid?
	jnz tryagain
	cmp edx,@flat:[046ch]	;did an interrupt occur in the meantime?
	jnz tryagain			;then do it again!
	xchg al,ah

;--- usually (counter mode 3) the timer is set to count down *twice*! 
;--- however, sometimes counter mode 2 is set!

	mov ch,cl
	and ch,0110B	;bit 1+2 relevant
	cmp ch,0110B	;counter mode 3?
	jnz @F

;--- in mode 3, PIN status of OUT0 will become bit 15

	shr ax,1
	and cl,80h
	or ah, cl
@@:

;--- now the counter is in AX (counts from FFFF to 0000)

	neg ax

;--- now the count is from 0 to FFFF

	ret
	align 4
_GetTimerValue endp

;--- this proc may be called during interrupt time, SS is unknown

_GetTimerValuems proc
	call _GetTimerValue

;--- the timer ticks are in EDX:AX, timer counts down 
;--- a 16bit value with 1,193,180 Hz -> 1193180/65536 = 18.20648 Hz
;--- which are 54.83 ms
;--- to convert in ms:
;--- 1. subticks in ms: AX / 1193
;--- 2. ticks in ms: EDX * 55
;--- 3. total 1+2

	push edx
	movzx eax,ax	;step 1
	cdq
	mov ecx, 1193
	div ecx
	mov ecx, eax
	pop eax 		;step 2
	mov edx, 55
	mul edx
	add eax, ecx	;step 3
	adc edx, 0
	ret
	align 4
_GetTimerValuems endp

if ?RTCRES

;--- the RTC timer ticks with 1024 Hz
;--- to convert into ms:
;--- ticks * 1000 / 1024 -> ticks * 125 / 128

getrtctimerticks proc
	mov eax, g_dwRTCTicks
	mov ecx, 125
	mul ecx
	shr eax, 7
	ret
	align 4
getrtctimerticks endp

externdef g_cntTimer:dword
externdef g_OldIrq08:fword
InitRTCTimer proto

installrtctimer proc

	@strace <"installrtctimer">
	mov g_dwGetTimerValuems, offset getrtctimerticks
	inc g_cntTimer				; to avoid that DeinitRTCTimer() is called in timer.asm
	.if (!word ptr g_OldIrq08+4)
		invoke InitRTCTimer
	.endif
	jmp g_dwGetTimerValuems
	align 4

installrtctimer endp
endif

if ?INIT

Init proc

if ?RTCRES
	test byte ptr [g_dwFlags],DKF_USERTC
	jz @F
	mov g_dwGetTimerValuems, offset installrtctimer
@@:
endif
	ret
	align 4

Init endp

endif

	end
